package cxf.spring.demo.storage;

import cxf.spring.demo.domain.message.Message;
import cxf.spring.demo.domain.message.MessagesList;
import cxf.spring.demo.domain.user.User;
import cxf.spring.demo.domain.user.UserList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * User: Vlad Vinichenko (akerigan@gmail.com)
 * Date: 06.03.2009
 * Time: 22:10:45
 */
public class ServerStorage {

    File basePath;

    Map<String, User> users = new TreeMap<String, User>();
    Map<String, Map<Integer, Message>> userMessagesMap = new TreeMap<String, Map<Integer, Message>>();
    AtomicInteger messageId = new AtomicInteger();

    public void setBasePath(String basePath) throws Exception {
        this.basePath = new File(basePath);
        if (!this.basePath.exists()) {
            boolean created = this.basePath.mkdirs();
            if (!created) {
                this.basePath = null;
            }
        } else {
            File usersDir = new File(basePath, "users");
            if (usersDir.exists()) {
                JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
                Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
                for (File file : usersDir.listFiles()) {
                    if (file.getName().endsWith(".xml")) {
                        User user = (User) unmarshaller.unmarshal(file);
                        users.put(user.getLogin(), user);
                    }
                }
            }
            File messagesDir = new File(basePath, "messages");
            if (messagesDir.exists()) {
                JAXBContext jaxbContext = JAXBContext.newInstance(Message.class);
                Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
                int maxId = 0;
                for (File file : usersDir.listFiles()) {
                    if (file.isDirectory()) {
                        String login = file.getName();
                        Map<Integer, Message> messageList = userMessagesMap.get(login);
                        if (messageList == null) {
                            messageList = new TreeMap<Integer, Message>();
                            userMessagesMap.put(login, messageList);
                        }
                        for (File file2 : file.listFiles()) {
                            if (file2.getName().endsWith(".xml")) {
                                Message message = (Message) unmarshaller.unmarshal(file2);
                                messageList.put(message.getId(), message);
                                if (message.getId() > maxId) {
                                    maxId = message.getId();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public User getUser(String login) throws Exception {
        return users.get(login);
    }

    public void updateUser(User user) throws Exception {
        if (user == null) {
            throw new IllegalArgumentException("User cant be null");
        }
        if (user.getLogin() == null) {
            throw new IllegalArgumentException("User login cant be null");
        }
        users.put(user.getLogin(), user);
        if (basePath != null) {
            persistUser(user);
        }
    }

    private void persistUser(User user) throws Exception {
        File usersDir = new File(basePath, "users");
        boolean dirExist = true;
        if (!usersDir.exists()) {
            dirExist = usersDir.mkdir();
        }
        if (dirExist) {
            File userFile = new File(usersDir, user.getLogin() + ".xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.marshal(user, userFile);
        }
    }

    public void sendMessage(String login, Message message) throws Exception {
        if (isValidUser(login)) {
            if (!login.equals(message.getSender())) {
                throw new IllegalStateException("Sending mail with different login not allowed");
            }
            message.setId(messageId.getAndAdd(1));
            List<String> recipients = message.getRecipients();
            if (recipients.size() > 0) {
                for (String recipient : recipients) {
                    if (isValidUser(recipient)) {
                        Map<Integer, Message> messageMap = userMessagesMap.get(recipient);
                        if (messageMap == null) {
                            messageMap = new TreeMap<Integer, Message>();
                            userMessagesMap.put(recipient, messageMap);
                        }
                        if (basePath != null) {
                            persistMessage(recipient, message);
                        }
                    }
                }
            } else {
                throw new IllegalArgumentException("Recipients not set");
            }
        } else {
            throw new IllegalArgumentException("User not exists");
        }
    }

    private void persistMessage(String user, Message message) throws Exception {
        File messagesDir = new File(basePath, "messages");
        boolean dirExist = true;
        if (!messagesDir.exists()) {
            dirExist = messagesDir.mkdir();
        }
        if (dirExist) {
            File userDir = new File(messagesDir, user);
            if (!userDir.exists()) {
                dirExist = userDir.mkdir();
            }
            if (dirExist) {
                File userFile = new File(messagesDir, String.format("%d.xml", message.getId()));
                JAXBContext jaxbContext = JAXBContext.newInstance(Message.class);
                Marshaller marshaller = jaxbContext.createMarshaller();
                marshaller.marshal(message, userFile);
            }
        }
    }

    public MessagesList getMessages(String login) throws Exception {
        if (isValidUser(login)) {
            MessagesList messagesList = new MessagesList();
            Map<Integer, Message> messageMap = userMessagesMap.get(login);
            if (messageMap != null) {
                for (int messageId : messageMap.keySet()) {
                    messagesList.addMessageId(messageId);
                }
            }
            return messagesList;
        } else {
            throw new IllegalArgumentException("User not exists");
        }
    }

    public Message getMessage(String login, int messageId) throws Exception {
        if (isValidUser(login)) {
            Map<Integer, Message> messageMap = userMessagesMap.get(login);
            if (messageMap != null) {
                return messageMap.get(messageId);
            } else {
                return null;
            }
        } else {
            throw new IllegalArgumentException("User not exists");
        }
    }

    public void delete(String login, MessagesList messagesList) throws Exception {
        if (isValidUser(login)) {
            Map<Integer, Message> messageMap = userMessagesMap.get(login);
            if (messageMap != null) {
                for (int messageId : messagesList.getMessageIds()) {
                    messageMap.remove(messageId);
                }
            }
        } else {
            throw new IllegalArgumentException("User not exists");
        }
    }

    private boolean isValidUser(String login) {
        return users.get(login) != null;
    }

    public UserList getUserList() {
        UserList userList = new UserList();
        userList.getLogins().addAll(users.keySet());
        return userList;
    }
}
